﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.VirtualEarth.MapControl;
using System.Windows.Media.Imaging;
using GraphDrawer.GraphProvider;

namespace GraphDrawer
{
    public partial class VirtualEarthControl : UserControl, GraphLayout.Interface.IGraph
    {
        Menu m_menu;
        String token = "12";
        GraphProviderServiceSoapClient cl;
        GraphLayout.GraphRepresentation.Graph gg;
        private Graph m_graph;
        

        public VirtualEarthControl(GraphProviderServiceSoapClient soapClient, Menu pMenu)
        {
            InitializeComponent();
            m_menu = pMenu;
            cl = soapClient;
            soapClient.StartSimulationCompleted += new EventHandler<StartSimulationCompletedEventArgs>(soapClient_StartSimulationCompleted);
            soapClient.GetGeoCodeCompleted += new EventHandler<GetGeoCodeCompletedEventArgs>(soapClient_GetGeoCodeCompleted);
            soapClient.StartSimulationAsync(m_menu.setupSelector.SimulationSetup, token);
            OldElements += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(VirtualEarthControl_OldElements);
            NewEdges += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(VirtualEarthControl_NewEdges);
        }

        void VirtualEarthControl_NewEdges(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                    foreach (GraphLayout.GraphRepresentation.EdgeItem item in e.NewItems)
                    {
                        var line = prefuse.action.layout.Layout.DrawLine(item.Source.X + ((GraphLayout.GraphRepresentation.NodeItem)item.Source).Width / 2,
								item.Source.Y + ((GraphLayout.GraphRepresentation.NodeItem)item.Source).Height / 2,
                                item.Target.X + ((GraphLayout.GraphRepresentation.NodeItem)item.Target).Width / 2,
                                item.Target.Y + ((GraphLayout.GraphRepresentation.NodeItem)item.Target).Height / 2);

                        item.VisualLine = line;
                        item.Children.Add(line);


                        item.SetValue(MapLayer.MapPositionProperty, new Microsoft.VirtualEarth.MapControl.Location(line.X1, line.Y1));
                        item.SetValue(MapLayer.MapPositionMethodProperty, PositionMethod.Center);

                        //item.SetValue(Canvas.ZIndexProperty, -10);
                        //this.Children.Add(item);
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                    foreach (GraphLayout.GraphRepresentation.EdgeItem item in e.OldItems)
                    {
                        (Map.FindName("PushpinLayer") as MapLayer).RemoveChild(item);
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    break;
                default:
                    break;
            }
        }

        void VirtualEarthControl_OldElements(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            
        }

        void soapClient_GetGeoCodeCompleted(object sender, GetGeoCodeCompletedEventArgs e)
        {
            Double latitude = e.Result[0];
            Double longitude = e.Result[1];
            AddPushpin(latitude, longitude, (GraphElement)e.UserState);
            var item = (GraphElement)e.UserState;
            PairKeyValue p1 = new PairKeyValue();
            p1.Key = "locationX";
            p1.Value = latitude.ToString();
            PairKeyValue p2 = new PairKeyValue();
            p2.Key = "locationY";
            p2.Value = longitude.ToString();
            item.Keys.Add(p1);
            item.Keys.Add(p2);
        }

        void soapClient_StartSimulationCompleted(object sender, StartSimulationCompletedEventArgs e)
        {
            m_graph = e.Result;
            Menu.map.Clear();

            gg = new GraphLayout.GraphRepresentation.Graph();
            gg.NewEdges += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(gg_NewEdges);
            gg.OldElements += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(gg_OldElements);
            gg.Nodes = new System.Collections.ObjectModel.ObservableCollection<GraphLayout.Interface.VisualItem>();
            gg.Edges = new System.Collections.ObjectModel.ObservableCollection<GraphLayout.GraphRepresentation.EdgeItem>();

            foreach (var item in m_graph.Vertices)
            {
                double? latitude = null;
                double? longitude = null;
                bool noPushpin = false;
                foreach (var key in item.Keys)
                {                    
                    if (key.Key == "locationX")
                    {
                        latitude = Convert.ToDouble(key.Value, System.Globalization.NumberFormatInfo.InvariantInfo);
                    }
                    if (key.Key == "locationY")
                    {
                        longitude = Convert.ToDouble(key.Value, System.Globalization.NumberFormatInfo.InvariantInfo);
                    }

                    if (latitude.HasValue && longitude.HasValue && !noPushpin)
                    {
                        AddPushpin(latitude.Value, longitude.Value, item);
                        noPushpin = true;
                    }

                }
                if (!latitude.HasValue && !longitude.HasValue)
                {
                    foreach (var key in item.Keys)
                    {
                        if (key.Key == "location")
                        {
                            cl.GetGeoCodeAsync(key.Value, item);
                            break;
                        }
                    }
                }


            }

			foreach (var item in m_graph.Edges) {
				var n1 = (from v in m_graph.Vertices
						  where v.Id == item.Source
						  select v).First();
				var n2 = (from v in m_graph.Vertices
						  where v.Id == item.Target
						  select v).First();

				GraphLayout.GraphRepresentation.EdgeItem e1 = new GraphLayout.GraphRepresentation.EdgeItem();
				e1.Target = Menu.map[n2];
				e1.Source = Menu.map[n1];
				e1.Graph = gg;

				//gg.Edges.Add(e1);

				var line = prefuse.action.layout.Layout.DrawLine(
						(e1.Source.Element as GraphElement).x,
						(e1.Source.Element as GraphElement).y,
						(e1.Target.Element as GraphElement).x,
						(e1.Target.Element as GraphElement).y);
						 

				e1.VisualLine = line;
				e1.Children.Add(line);

				//e1.SetValue(MapLayer.MapPositionProperty, new Microsoft.VirtualEarth.MapControl.Location(line.X1, line.Y1));
				/*e1.SetValue(MapLayer.MapPositionProperty, new Microsoft.VirtualEarth.MapControl.MapPolyline() {
					Locations = new LocationCollection() {
						new Location(line.X1, line.Y1),
						new Location(line.X2, line.Y2)
					}
				});*/
				e1.SetValue(MapLayer.MapPositionMethodProperty, PositionMethod.Center);

				e1.SetValue(Canvas.ZIndexProperty, -10);

				//(Map.FindName("PushpinLayer") as MapLayer).AddChild(e1);
				(Map.FindName("PushpinLayer") as MapLayer).AddChild(
					new Microsoft.VirtualEarth.MapControl.MapPolyline() {
						Locations = new LocationCollection() {
							new Location(line.X1, line.Y1),
							new Location(line.X2, line.Y2)
						},
						Stroke = new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)),
						StrokeThickness = 1.0,
					}
				);
			}

        }

        void gg_NewEdges(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            
        }

        void gg_OldElements(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            
        }

        private void AddPushpin(double latitude, double longitude, GraphElement elem)
        {
            var node = (GraphLayout.GraphRepresentation.NodeItem)GleeGraphDrawer.CreateNodeCanvas(elem, m_menu);

            gg.Nodes.Add(node);
            ((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).Graph = gg;
            gg.Nodes.Last().Element = elem;
            elem.x = latitude;
            elem.y = longitude;

            ((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).MouseEnter += new MouseEventHandler(GleeGraphDrawer.SetInfoPanel);
            ((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).MouseLeave += new MouseEventHandler(GleeGraphDrawer.ResetInfoPanel);
			((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).NodeSelected += new MouseEventHandler(nodeCanvas_NodeSelected);

            node.SetValue(MapLayer.MapPositionProperty, new Microsoft.VirtualEarth.MapControl.Location(latitude, longitude));
            node.SetValue(MapLayer.MapPositionMethodProperty, PositionMethod.Center);

            Menu.map.Add(elem, node);

            (Map.FindName("PushpinLayer") as MapLayer).AddChild(node);
        }

		void nodeCanvas_NodeSelected(object sender, MouseEventArgs e) {
			var curr = sender as GraphLayout.GraphRepresentation.NodeItem;
			var prev = curr.Graph.PreviousSelectedNode as GraphLayout.GraphRepresentation.NodeItem;

			if (prev != null) {
				GraphElement n = prev.Element as GraphElement;

				String text = String.Empty;
				foreach (var description in n.Keys) {
					if (description.Key == "stateName") {
						text = description.Value;
						break;
					}
				}

				((Ellipse)prev.Children[0]).Fill = m_menu.GetColorForDisease(text);
				((Ellipse)prev.Children[0]).Stroke = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50));
				((Ellipse)prev.Children[0]).StrokeThickness = 1.0;
			}
			if (curr != null) {
				GraphElement n = curr.Element as GraphElement;
               
                var ditails = (Map.FindName("ditails") as PatientDetails);
                ditails.UpdateDetails(n.Keys);

                

				((Ellipse)curr.Children[0]).Fill = new SolidColorBrush(Color.FromArgb(128, 55, 55, 100));
				((Ellipse)curr.Children[0]).Stroke = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
				((Ellipse)curr.Children[0]).StrokeThickness = 2.0;
			}
		}

        #region IGraph Members

        public event System.Collections.Specialized.NotifyCollectionChangedEventHandler NewEdges;

        public event System.Collections.Specialized.NotifyCollectionChangedEventHandler OldElements;

        public System.Collections.ObjectModel.ObservableCollection<GraphLayout.Interface.VisualItem> Nodes
        {
            get { return gg.Nodes; }
        }

        public System.Collections.ObjectModel.ObservableCollection<GraphLayout.GraphRepresentation.EdgeItem> Edges
        {
            get { return gg.Edges; }
        }

        public GraphLayout.Interface.VisualItem SelectedNode
        {
            get
            {
                //throw new NotImplementedException();
                return gg.Nodes[1];
            }
            set
            {
                //throw new NotImplementedException();
            }
        }

        public GraphLayout.Interface.VisualItem PreviousSelectedNode
        {
            get
            {
                //throw new NotImplementedException();
                return gg.Nodes[0];
            }
            set
            {
                //throw new NotImplementedException();
            }
        }

        #endregion
    }
}
